package top.tangyh.lamp.care.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.util.concurrent.AtomicDouble;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.tangyh.lamp.care.common.ExeYaoEventTypeEnum;
import top.tangyh.lamp.care.common.ExeYaoStatusNewEnum;
import top.tangyh.lamp.care.entity.BIoRecord;
import top.tangyh.lamp.care.mapper.BHl7YzYaoPlanMapper;
import top.tangyh.lamp.care.mapper.BIoRecordMapper;
import top.tangyh.lamp.care.service.BHl7YzYaoPlanService;
import top.tangyh.basic.base.service.impl.SuperServiceImpl;
import top.tangyh.lamp.care.manager.BHl7YzYaoPlanManager;
import top.tangyh.lamp.care.entity.BHl7YzYaoPlan;
import top.tangyh.lamp.care.vo.query.YzYaoPlanQueryVO;
import top.tangyh.lamp.care.vo.result.ExeYaoEventOutVO;
import top.tangyh.lamp.care.vo.result.HandoverMedicineVo;
import top.tangyh.lamp.care.vo.save.BHl7YzYaoPlanSaveVO;
import top.tangyh.lamp.care.vo.update.BHl7YzYaoPlanUpdateVO;
import top.tangyh.lamp.care.vo.result.BHl7YzYaoPlanResultVO;
import top.tangyh.lamp.care.vo.query.BHl7YzYaoPlanPageQuery;
import top.tangyh.lamp.care.vo.update.UpdateIsShowCareVO;
import top.tangyh.lamp.common.constant.CommonConstant;
import top.tangyh.lamp.common.utils.IcuDateUtils;
import top.tangyh.lamp.common.utils.PDateUtils;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;



/**
 * <p>
 * 业务实现类
 * 医嘱执行计划表
 * </p>
 *
 * @author zqb
 * @date 2024-07-22 15:09:13
 * @create [2024-07-22 15:09:13] [zqb] [代码生成器生成]
 */
@Slf4j
@RequiredArgsConstructor
@Service
@Transactional(readOnly = true)
public class BHl7YzYaoPlanServiceImpl extends SuperServiceImpl<BHl7YzYaoPlanManager, Integer, BHl7YzYaoPlan> implements BHl7YzYaoPlanService {


    public static final String MED_DELIMITER = " + ";
    public static final String USED = "used";
    public static final String LAST_TIME = "lastTime";
    public static final int INIT_SPEED = 0;
    public static final double INIT_COUNT = 0D;
    public static final double DIFF_COUNT = 1D;
    private final BHl7YzYaoPlanMapper bHl7YzYaoPlanMapper;

    private final BIoRecordMapper bIoRecordMapper;
    
    @Override
    public HandoverMedicineVo getExeYaoDataByHandOver(String hospitalNumber, Long currentDate, Long workStartTime, Long workEndTime) {
        //先不做这块
        return null;
    }

    @Override
    public List<BHl7YzYaoPlan> selectPlanByQuery(YzYaoPlanQueryVO queryVO) {
        return bHl7YzYaoPlanMapper.selectListByQuery(queryVO);
    }

    /**
     * 获取事件总用量 如果超过总量则不记录
     *
     * @param eventList
     * @return
     */
    @Override
    public Map<String, Number> getTotalUsed(List<ExeYaoEventOutVO> eventList, double total) {
        AtomicDouble usedCounts = new AtomicDouble(0);
        AtomicLong eventOverTimestamp = new AtomicLong(0);
        eventList.forEach(eventOutVO -> handleEventUsed(eventOutVO, eventOverTimestamp, usedCounts, total));
        Map<String, Number> map = new HashMap<>();
        map.put(USED, usedCounts);
        map.put(LAST_TIME, eventOverTimestamp);
        return map;
    }

    /**
     * 根据事件计算已用量
     *
     * @param eventOutVO
     * @param usedCounts
     */
    private void handleEventUsed(ExeYaoEventOutVO eventOutVO, AtomicLong eventOverTimestamp, AtomicDouble usedCounts, double total) {
        long currentTime = DateUtil.date().getTime();
        //不处理超越当前时间的事件
        if (PDateUtils.getTimestampOfDateTime(eventOutVO.getEventTime()) <= currentTime) {
            String eventType = eventOutVO.getEventType();
            double speed = eventOutVO.getSpeed().doubleValue();
            Integer currentSpeed = eventOutVO.getCurrentSpeed();
            //快推事件的已用量直接减去
            if (ExeYaoEventTypeEnum.FAST_PUSH.getEventType().equals(eventType)) {
                double totalUsed = NumberUtil.round(usedCounts.get() + speed, 1).doubleValue();
                usedCounts.set(totalUsed);
            }
            //计算已用量
            long eventTime = PDateUtils.getTimestampOfDateTime(eventOutVO.getEventTime());
            LocalDateTime eventOverTime = eventOutVO.getEventOverTime();
            //该事件已闭环 可以计算出这段时间的已用量
            if (eventOverTime != null && currentSpeed != 0) {
                long overTime = PDateUtils.getTimestampOfDateTime(eventOverTime);
                if (currentTime < overTime) {
                    overTime = currentTime;
                }
                double countUsed = countUsed(overTime, eventTime, currentSpeed);
                double totalUsed = getTotalUsed(usedCounts.get(), countUsed);
                usedCounts.set(totalUsed);
                eventOverTimestamp.set(overTime);
            } else if (eventOverTime == null && currentSpeed != 0) {
                //进行中的事件 用当前时间来计算使用 注意这里存在过去的进行中
                double countUsed = countUsed(currentTime, eventTime, currentSpeed);
                double totalUsed = getTotalUsed(usedCounts.get(), countUsed);
                //如果计算出的总量超过总量 则不记录已用量
                if (totalUsed <= total) {
                    usedCounts.set(totalUsed);
                    eventOverTimestamp.set(currentTime);
                } else {
                    eventOverTimestamp.set(eventTime);
                }
            }
        }
    }

    /**
     * 计算总的已用量 保留一位小数
     *
     * @param lastUsed
     * @param currentUsed
     * @return
     */
    private double getTotalUsed(double lastUsed, double currentUsed) {
        return lastUsed + currentUsed;
    }

    /**
     * 根据时间段和速度计算已使用量 保留一位小数
     *
     * @param currentEventTime 当前的时间
     * @param lastEventTime    上一次的时间
     * @param lastSpeed        上一次的速度
     */
    private double countUsed(long currentEventTime, long lastEventTime, int lastSpeed) {
        long runningTime = currentEventTime - lastEventTime;
        double runHours = IcuDateUtils.getHoursByIntervalTimes(runningTime);
        double usedCounts = lastSpeed * runHours;
        return usedCounts;
    }


    @Override
    public List<BHl7YzYaoPlan> getYaoPlanListByGroupId(String groupId) {
        LambdaUpdateWrapper<BHl7YzYaoPlan> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(BHl7YzYaoPlan::getGroupId, groupId)
                .eq(BHl7YzYaoPlan::getIsDeleted, CommonConstant.NO_NUMBER);
        return bHl7YzYaoPlanMapper.selectList(updateWrapper);
    }

    @Override
    public void updateDeleteStatusByGroupId(String groupId,Integer status) {
        LambdaUpdateWrapper<BHl7YzYaoPlan> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(BHl7YzYaoPlan::getGroupId, groupId);
        BHl7YzYaoPlan yaoPlanPO = new BHl7YzYaoPlan();
        yaoPlanPO.setIsDeleted(status);
        bHl7YzYaoPlanMapper.update(yaoPlanPO, updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateIsShowCare(UpdateIsShowCareVO updateIsShowCareVO) {
        LambdaUpdateWrapper<BHl7YzYaoPlan> updateQueryWrapper = Wrappers.<BHl7YzYaoPlan>lambdaUpdate()
                .eq(BHl7YzYaoPlan::getGroupId, updateIsShowCareVO.getGroupId())
                .eq(BHl7YzYaoPlan::getPlanTime, new Date(updateIsShowCareVO.getPlanTime()))
                .eq(BHl7YzYaoPlan::getExeStatus, ExeYaoStatusNewEnum.EXECUTED.getStatusCode())
                .set(BHl7YzYaoPlan::getIsShowCare, updateIsShowCareVO.getIsShowCare());
        Integer rows = bHl7YzYaoPlanMapper.update(null, updateQueryWrapper);
        LambdaUpdateWrapper<BIoRecord> ioupdateQueryWrapper = Wrappers.<BIoRecord>lambdaUpdate()
                .eq(BIoRecord::getGroupId, updateIsShowCareVO.getGroupId())
                .eq(BIoRecord::getPlanTime, new Date(updateIsShowCareVO.getPlanTime()))
                .set(BIoRecord::getIsShowCare, updateIsShowCareVO.getIsShowCare());
        bIoRecordMapper.update(null,ioupdateQueryWrapper);
        return rows;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateYtCount(UpdateIsShowCareVO updateIsShowCareVO) {
        LambdaUpdateWrapper<BHl7YzYaoPlan> updateQueryWrapper = Wrappers.<BHl7YzYaoPlan>lambdaUpdate()
                .eq(BHl7YzYaoPlan::getGroupId, updateIsShowCareVO.getGroupId())
                .eq(BHl7YzYaoPlan::getPlanTime, new Date(updateIsShowCareVO.getPlanTime()))
                .eq(BHl7YzYaoPlan::getExeStatus, ExeYaoStatusNewEnum.EXECUTED.getStatusCode())
//                .set(null != updateIsShowCareVO.getYt_count(), BHl7YzYaoPlan::getYtCount, updateIsShowCareVO.getYt_count())
                .set(BHl7YzYaoPlan::getInputType, updateIsShowCareVO.getInputType());
        Integer rows = bHl7YzYaoPlanMapper.update(null, updateQueryWrapper);
        return rows;
    }

    @Override
    public List<BHl7YzYaoPlan> selectListByGroupIdPlanTime(String groupId, String planTime, String hospitalNumber) {
        return bHl7YzYaoPlanMapper.selectListByGroupIdPlanTime(groupId, planTime, hospitalNumber);
    }

}


